﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Mvc;

using ProjectBase.Core;
using ProjectBase.Core.Web;
using ProjectBase.Mvc;

namespace Survey.Filters
{
    /// <summary>
    ///     Logs 6 basic OnActionEvents Prefixes and Suffixes
    ///     1) OnAuthorization
    ///     2) OnActionExecuting 3) OnActionExecuted
    ///     4) OnException
    ///     5) OnResultExecuting 6) OnResultExecuted.
    ///     Important is to have the Project.Business 'appender' and 'logger' set
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
    public class ActionLoggerAttribute
        : FilterAttribute, IActionFilter, IExceptionFilter, IAuthorizationFilter, IResultFilter, IPublishingReporter
    {
        #region IActionFilter Members
        /// <summary>
        ///     Logs basically Time when Action started
        /// </summary>
        /// <param name = "filterContext"></param>
        public virtual void OnActionExecuting(ActionExecutingContext filterContext)
        {
            this.PublishDebug(() =>
                "OnActionExecuting: Action started URI: {0}".FormatWith(
                    filterContext.HttpContext.Request.
                        Url.AbsoluteUri));
        }

        /// <summary>
        ///     Logs basically Time when Action finsihed
        /// </summary>
        public virtual void OnActionExecuted(ActionExecutedContext filterContext)
        {
            this.PublishDebug(() =>
                "OnActionExecuted: Action finished URI: {0}".FormatWith(
                    filterContext.HttpContext.Request.
                        Url.AbsoluteUri));
        }
        #endregion

        #region IAuthorizationFilter Members
        /// <summary>
        ///     Logs success or not when Authorizing:
        ///     1) Error for UNauthorized
        ///     2) Debug for authorized
        /// </summary>
        /// <param name = "filterContext"></param>
        public virtual void OnAuthorization(AuthorizationContext filterContext)
        {
            this.PublishInfo(() => "------------ START ------------");
            this.PublishInfo(() => "----" + filterContext.ActionDescriptor.ActionName + "----");
            this.PublishInfo(() => "----" + filterContext.ActionDescriptor.ControllerDescriptor.ControllerName + "----");

            this.PublishDebug(() => "OnAuthorization: URI: {0}".FormatWith(filterContext.HttpContext.Request.Url.AbsoluteUri));
            if (filterContext.Result is HttpUnauthorizedResult)
            {
                // unathorized
                this.PublishError(() =>
                    "OnAuthorization: User '{0}' was NOT authorized ".FormatWith(
                        Thread.CurrentPrincipal.
                            Identity.Name));
            }
            else
            {
                // OK
                this.PublishInfo(() => "OnAuthorization: authorized " + Thread.CurrentPrincipal.Identity.Name);
            }
        }
        #endregion

        #region IExceptionFilter Members
        /// <summary>
        ///     Logs Exception
        /// </summary>
        /// <param name = "filterContext"></param>
        public virtual void OnException(ExceptionContext filterContext)
        {
            this.PublishFatal("OnException: exception was thrown", filterContext.Exception);
            if (filterContext.Exception.InnerException.Is())
            {
                this.PublishFatal("OnException: InnerException ", filterContext.Exception.InnerException);
            }
        }
        #endregion

        #region IResultFilter Members
        /// <summary>
        ///     Logs basically Time when Result processing started
        /// </summary>
        public virtual void OnResultExecuting(ResultExecutingContext filterContext)
        {
            this.PublishDebug(() =>
                "OnResultExecuting: Action started URI: {0}".FormatWith(
                    filterContext.HttpContext.Request.Url.AbsoluteUri));
        }

        /// <summary>
        ///     Logs basically: 1) Time when Result processing finished
        ///     2) Session size
        /// </summary>
        public virtual void OnResultExecuted(ResultExecutedContext filterContext)
        {
            this.PublishDebug(() =>
                "OnResultExecuted: Action finished URI: {0}".FormatWith(
                    filterContext.HttpContext.Request.Url.AbsoluteUri));

            this.PublishWarning(() => ReportSessionSize(filterContext));
        }

        protected virtual string ReportSessionSize(ResultExecutedContext filterContext)
        {
            var session = filterContext.HttpContext.Session;
            int bytes = CountSessionBytes(filterContext, session);

            return bytes > 500000
                ? "OnResultExecuted Session size is TOO HIGH: {0} KB ".FormatWith(bytes / 1024)
                : "OnResultExecuted Session size is OK: {0} KB ".FormatWith(bytes / 1024);
        }

        protected virtual int CountSessionBytes(ResultExecutedContext filterContext, HttpSessionStateBase session)
        {
            var bytes = 0;
            if (session.IsNull())
            {
                return bytes;
            }

            foreach (var obj in session)
            {
                if (obj.IsNull())
                {
                    continue;
                }
                bytes += filterContext.ToByteArray(session[obj.ToString()]).Length;
            }
            return bytes;
        }

        #endregion
    }
}